/*****************************************************************************
 Analizador sintactico para el trabajo practico
******************************************************************************/
%{
#include "traductor.h"


void yyerror(char *);
extern FILE *yyin;
FILE *out;
extern int yylineno;


int traducir=1;
int scope=0;

struct list_head *tablaVariables[MAX_VISIBILIDAD] = {NULL};
struct list_head *tablaFunciones = NULL;


struct variable_por_funcion variables_por_funcion[CANTIDAD_VARIABLES];
int numero_funcion = 0;
int indice_vpf = 0;


void nueva_vpf (char *nombre, int tipo, int compuesto, int funcion);


// para el debug del parser
yydebug = 1;

static void
yyprint (char *imprime)
{
    fprintf(stderr, "%s", imprime);
}


%}

%union {
    char *lexema;
    struct funcion *fun;
    int tipo;
    struct argumentos *args;
    struct list_head *lista;
    struct id *id;
};


%token <tipo> INTEGER CHAR FLOAT VOID IF ELSE FOR WHILE DO
%token <lexema> ID CARACTER ENTERO REAL LITERAL PRINTF
%token TIPO_VACIO
%token TIPO_ERROR
%token RETURN
%nonassoc IFX
%nonassoc ELSE
%left AND OR
%right '!'
%left '=' '<' '>' EQUALEQUAL DISCTINCT MINEQUAL MAYEQUAL 
%left '+' '-' MINUSEQUAL PLUSEQUAL PLUSPLUS MINUSMINUS 
%left '*' '/' '%' MULEQUAL DIVEQUAL 
%right UMINUS
%type <id> variable expresion proposicion proposicionDoWhile listaProposiciones listaDeclaraciones proposicionCompuesta asignacion expresionAsignacion reglaElse
%type <fun> funcion 
%type <tipo> declaracion tipo 
%type <args> listaParams listaExpresiones
%type <lista> listaVar listaVariables


%%

/*  Muy interesante el tema del "error" como manejo de errores. Segun lei, en el
    ejemplo 3-2 del libro, paginas 67 y 68, muestra como se puede hacer que 
    bison entre en modo de panico, y vaya descartando tokens, hasta llegar de
    nuevo a un estado consistente. Muy Interesante de implementarlo. */


inicio:
    listaFunciones
        {
            if(!verificaMain())
                errorSemantico(""," No existe una funcion main\n");
        }

    |   listaVar listaFunciones
        {
            if(!verificaMain())
                errorSemantico(""," No existe una funcion main\n");
        }

    ;
        

listaVar: 
    declaracion

    |   tipo ID '(' listaParams ')' ';'
        {
            if((struct variable *)buscaVariable($2)) {
                errorSemantico($2," intentando redefinir como un tipo de simbolo distinto\n");
            } else {
                struct funcion *f = (struct funcion *)buscarNodoFuncion($2);
                if(f!=NULL) {
                    errorSemantico($2," ya existe esa funcion ");
                } else {
                    if($4!=NULL){
                        f = (struct funcion *)crearNodoFuncion($1,$2,$4);
                        f->prototipo = 1;
                        agregarNodoFuncion(f);
                    }
                }
            }
            decrementarScope(); 
        }

    |   listaVar declaracion

    |   listaVar tipo ID '(' listaParams ')' ';'
        { 
            if((struct variable *)buscaVariable($2)) {
                errorSemantico($2," intentando redefinir como un tipo de simbolo distinto\n");
            } else {
                struct funcion *f = (struct funcion *)buscarNodoFuncion($2);
                if(f != NULL) {
                    errorSemantico($2," ya existe esa funcion ");
                } else {
                    if($5 != NULL) {
                        f = (struct funcion *)crearNodoFuncion($1,$2,$5);
                        f->prototipo = 1;
                        agregarNodoFuncion(f);
                    }
                }
            }
            decrementarScope(); 
        }

    |   error declaracion  { yyerrok; };

    |   error tipo ID '(' listaParams ')' ';'
        { 
            if((struct variable *)buscaVariable($3)) {
                errorSemantico($3," intentando redefinir como un tipo de simbolo distinto\n");
            } else {
                struct funcion *f = (struct funcion *)buscarNodoFuncion($3);
                if(f != NULL) {
                    errorSemantico($3," ya existe esa funcion ");
                } else {
                    if($5!=NULL) {
                        f = (struct funcion *)crearNodoFuncion($2,$3,$5);
                        f->prototipo = 1;
                        agregarNodoFuncion(f);
                    }
                }
            }
            decrementarScope(); 
            { yyerrok; }
            ;
        }

    ;


listaFunciones:
    funcion
    |   listaFunciones funcion 
    ;
    

funcion:
    tipo ID '(' listaParams ')' proposicionCompuesta
    {
        if((struct variable *)buscaVariable($2)) {
            errorSemantico($2," intentando redefinir como un tipo de simbolo distinto\n");
            $$ = NULL;
        } else {
            struct funcion *f = (struct funcion *)buscarNodoFuncion($2);

            if(f!=NULL && buscarNodoFuncionR($2)) {
                errorSemantico($2," ya existe esa funcion ");
                $$ = NULL;
            } else {
                if(f!=NULL && !compararArgumentos(f->listaArgumentos,$4,f->lexema)) {
                    errorSemantico($2," no se puede definir una funcion que no coincida con el prototipo");
                    $$ = NULL;
                } else {
                    if($4!=NULL && $6!=NULL) {
                        agregar_funcion_vpf (numero_funcion);
                        f = (struct funcion *)crearNodoFuncion($1,$2,$4);
                        f->prototipo=0;
                        agregarNodoFuncion(f);
                        $$ = f;
                        yyprint("Parser: linea 183 al 185. Aqui es donde imprime en el archivo de salida.\n");
                        imprimirFuncion(f, numero_funcion);
                        imprimirBuffer($6->buffer);
                        imprimirTexto("\n\0");
                        numero_funcion++;
                    }

                }
            }
        }
        decrementarScope();
    }

    |   tipo ID '(' error ')' proposicionCompuesta
    {
        yyerrok;
    }

    ;
             

listaParams:
    tipo ID
    {
        incrementarScope();
        /* creacion de la variable */
        if((struct variable *)buscaVariableScope($2,scope)) {
            errorSemantico($2,"la variable ya fue declarada\n");
            $$ = NULL;
        } else {
            struct variable *v = (struct variable *)crearNodoVariable();
            v->lexema=strdup($2);
            v->tipo = $1;
            v->compuesto=SIMPLE;
            agregarVariable(v); 

            /* creacion de la lista de argumentos */
            $$=(struct argumentos*)crearNodoArgumentos();
            agregarNodoArgumento($1,$2,$$);
        }      
    }

    | listaParams ',' tipo ID
    {
        if((struct variable *)buscaVariableScope($4,scope)) {
            errorSemantico($4,"la variable ya fue declarada\n");
            $$ = NULL;
        } else {
            struct variable *v = (struct variable *)crearNodoVariable();
            v->lexema=strdup($4);
            v->tipo = $3;
            v->compuesto=SIMPLE;
            agregarVariable(v);
            if($1 != NULL) {
                agregarNodoArgumento($3,$4,$1);
                $$=$1;
            } else {
                $$ = NULL;
            }
        }
    }

    | VOID
    {
        incrementarScope();
        $$=(struct argumentos*)crearNodoArgumentos();
        agregarNodoArgumento(TIPO_VACIO,"",$$);
    }

    | listaParams ',' error
    {
        yyerrok;
        $$ = NULL;
    }

    | /* producion -> vacia*/
    {
        incrementarScope();
        $$ = (struct argumentos*)crearNodoArgumentos();
        agregarNodoArgumento(TIPO_VACIO,"",$$);
    }

    ;


tipo:
    INTEGER
    {
        $$ = ENTERO;
    }

    | CHAR
    {
        $$=CARACTER;
    }

    | FLOAT
    {
        $$=REAL;
    }

    | VOID
    {
        $$=TIPO_VACIO;
    }

    ;            


variable:
    ID
    {      
        $$=(struct id*)crearNodoId();
        $$->lexema=strdup($1);
        $$->compuesto=SIMPLE;

        yyprint("Parser. Agregar texto antes: linea 298\n");
        $$->buffer = (struct textoImpresion*)agregarTextoAntes("\0",$$->buffer);
        yyprint("Parser. Agregar texto despues: linea 300\n");
        agregarTextoDespues($1,$$->buffer);
    }

    | ID '[' expresion ']'
    {
        $$=(struct id*)crearNodoId();
        $$->lexema=strdup($1);
        $$->compuesto=VECTOR;
        
        yyprint("Parser. Agregar texto antes: linea 310\n");
        $$->buffer = (struct textoImpresion*)agregarTextoAntes("\0",$$->buffer);
        yyprint("Parser. Agregar texto despues: linea 312 y 313\n");
        agregarTextoDespues($1,$$->buffer);
        agregarTextoDespues("[\0",$$->buffer);
        
        if($3!=NULL)
            agregarLista($3->buffer,$$->buffer);
        
        yyprint("Parser. Agregar texto despues: linea 319\n");
        agregarTextoDespues("]\0",$$->buffer);
    }

    | ID '[' expresion ']''[' expresion ']'
    {
        $$=(struct id*)crearNodoId();
        $$->lexema=strdup($1);
        $$->compuesto=MATRIZ;

        yyprint("Parser. Agregar texto antes: linea 329\n");
        $$->buffer = (struct textoImpresion*)agregarTextoAntes("\0",$$->buffer);
        yyprint("Parser. Agregar texto despues: linea 331 y 332\n");
        agregarTextoDespues($1,$$->buffer);
        agregarTextoDespues("[\0",$$->buffer);
        
        if($3!=NULL)
            agregarLista($3->buffer,$$->buffer);
        
        yyprint("Parser. Agregar texto despues: linea 338 y 339\n");
        agregarTextoDespues(",\0",$$->buffer);

        
        if($6!=NULL)
            agregarLista($6->buffer,$$->buffer);
        
        yyprint("Parser. Agregar texto despues: linea 345\n");
        agregarTextoDespues("]\0",$$->buffer);
    }        

    ;


expresion:
    variable
    {
        struct variable *v = (struct variable *)buscaVariable($1->lexema);

        if(v==NULL) {
            errorSemantico($1->lexema,"La variable no fue declarada\n");
            $$=NULL;
        } else {
            if($1->compuesto != v->compuesto) {
                errorSemantico($1->lexema," Se refirio a la variable con un tipo errado\n");
                $$=NULL;
            } else {
                $$=$1;
                $$->tipo=v->tipo;
            }
        }

    }

    | ENTERO
    { 
        $$=(struct id*)crearNodoId();

        yyprint("Parser. Agregar texto antes: linea 376\n");
        $$->buffer = (struct textoInforme *)agregarTextoAntes($1,$$->buffer);
        $$->tipo = ENTERO;

    }

    | REAL
    {
        $$=(struct id*)crearNodoId();
        
        yyprint("Parser. Agregar texto antes: linea 386\n");
        $$->buffer = (struct textoInforme *)agregarTextoAntes($1,$$->buffer);
        $$->tipo = REAL;
    }

    | CARACTER
    {
        $$=(struct id*)crearNodoId();
        
        yyprint("Parser. Agregar texto antes: linea 395\n");
        $$->buffer = (struct textoInforme *)agregarTextoAntes($1,$$->buffer);
        $$->tipo = CARACTER;
    }

    | LITERAL
    {  
        $$=(struct id*)crearNodoId();
        
        yyprint("Parser. Agregar texto antes: linea 404\n");
        $$->buffer = (struct textoInforme *)agregarTextoAntes($1,$$->buffer);
        $$->tipo = LITERAL;
    }

    | expresion '+' expresion
    {
        if($1!=NULL && $3!=NULL) {
            if($1->tipo==$3->tipo) {
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 352\n");
                agregarTextoDespues("+\0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento sumar dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion '-' expresion
    {
        if($1!=NULL && $3!=NULL) {
            if($1->tipo==$3->tipo) {
                $$=$1; 
                yyprint("Parser. Agregar texto despues: linea 267\n");
                agregarTextoDespues("-\0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento restar dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion '*' expresion
    {
        if($1!=NULL && $3!=NULL) {
            if($1->tipo==$3->tipo){
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 446\n");
                agregarTextoDespues("*\0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento multiplicar dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion '/' expresion
    {
        if($1!=NULL && $3!=NULL) {
             if($1->tipo==$3->tipo) {
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 462\n");
                switch ($1->tipo) {
                    case ENTERO:
                        agregarTextoDespues(" div \0",$$->buffer);
                        break;
                    case REAL:
                        agregarTextoDespues("/\0",$$->buffer);
                        break;
                    default:
                        errorSemantico("","Pascal no admite operacion de division con otros tipos que no sean Integer y Double.\n");
                        $$=NULL;
                }
                agregarLista($3->buffer,$$->buffer);
             } else {
                errorSemantico("","Se intento dividir dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion '%' expresion
    {
        if($1!=NULL && $3!=NULL){
             if($1->tipo==$3->tipo){
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 478\n");
                agregarTextoDespues(" mod \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
             }else{
                errorSemantico("","Se intento modulo dos tipos diferentes\n");
                $$=NULL;
            }
        
        }else
            $$=NULL;
    }

    | expresion '<' expresion
    {
        if($1!=NULL && $3!=NULL){
             if($1->tipo==$3->tipo){
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 495\n");
                agregarTextoDespues(" < \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
             }else{
                errorSemantico("","Se intento menor que de dos tipos diferentes\n");
                $$=NULL;
            }
        
        }else
            $$=NULL;
    }

    | expresion '>' expresion
    {
        if($1!=NULL && $3!=NULL) {
            if($1->tipo==$3->tipo) {
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 512\n");
                agregarTextoDespues(" > \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento mayor que en dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | '-' expresion %prec UMINUS
    {
        if($2!=NULL){
            $$=(struct id*)crearNodoId();
            yyprint("Parser. Agregar texto antes: linea 444\n");
            $$->buffer=(struct textoInforme *)agregarTextoAntes("-\0",$$->buffer);
            agregarLista($2->buffer,$$->buffer);
            $$->tipo=$2->tipo;
         }else
            $$=NULL;
         
     }

    | '(' expresion ')'
    {
        if($2!=NULL) {
            $$=(struct id*)crearNodoId();
            yyprint("Parser. Agregar texto antes: linea 540\n");
            $$->buffer=(struct textoInforme *)agregarTextoAntes("(\0",$$->buffer);
            agregarLista($2->buffer,$$->buffer);
            yyprint("Parser. Agregar texto despues: linea 543\n");
            agregarTextoDespues(")\0",$$->buffer);
            $$->tipo = $2->tipo;
         }else
            $$=NULL;
    }

    | expresion AND expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 555\n");
                agregarTextoDespues(" and \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento AND de dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion EQUALEQUAL expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 571\n");
                agregarTextoDespues(" = \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento comparar de dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion DISCTINCT expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 587\n");
                agregarTextoDespues(" <> \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento comparar de dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion MINEQUAL expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 603\n");
                agregarTextoDespues(" <= \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            } else {
                errorSemantico("","Se intento comparar de dos tipos diferentes\n");
                $$=NULL;
            }
        } else
            $$=NULL;
    }

    | expresion MAYEQUAL expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 619\n");
                agregarTextoDespues(" >= \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento comparar de dos tipos diferentes\n");
                $$=NULL;
            }
        }else
            $$=NULL;
    }                           

    | expresion OR expresion
    {
        if($1!=NULL && $3!=NULL){
            if($1->tipo==$3->tipo){
                $$=$1;
                yyprint("Parser. Agregar texto despues: linea 635\n");
                agregarTextoDespues(" or \0",$$->buffer);
                agregarLista($3->buffer,$$->buffer);
            }else{
                errorSemantico("","Se intento OR de dos tipos diferentes\n");
                $$=NULL;
            }
        }else
            $$=NULL;
    }

    | '!' expresion
    {
        if($2!=NULL){
            $$=(struct id*)crearNodoId();
            yyprint("Parser. Agregar texto antes: linea 650\n");
            $$->buffer=(struct textoInforme *)agregarTextoAntes(" not \0",$$->buffer);
            agregarLista($2->buffer,$$->buffer);
            $$->tipo=$2->tipo;
         }else
            $$=NULL;
    }

    | ID '(' listaExpresiones ')'
    {
        if((struct variable *)buscaVariable($1)){
            errorSemantico($1," no es una funcion\n");
        }else{                                        
            struct funcion *f = (struct funcion *)buscarNodoFuncion($1);
            if(f==NULL){
                errorSemantico($1," No existe la funcion ");
                $$=NULL;
            }else{
                if($3!=NULL){
                    if(compararArgumentos(f->listaArgumentos,$3,$1)){
                        $$=(struct id*)crearNodoId();
                        yyprint("Parser. Agregar texto antes: linea 671\n");
                        $$->buffer=(struct textoInforme *)agregarTextoAntes($1,$$->buffer);
                        agregarTextoDespues("(\0",$$->buffer);
                        if($3->cArg>0)
                            agregarLista($3->buffer,$$->buffer);
                        yyprint("Parser. Agregar texto despues: linea 675\n");
                        agregarTextoDespues(")\0",$$->buffer);
                        $$->tipo = f->retorno;
                    }else{
                        $$=NULL;
                    }
                }else
                    $$=NULL;
            }
        }
    }

    |  PRINTF '(' listaExpresiones ')'
    {
        if($3!=NULL){
            $$=(struct id*)crearNodoId();
            yyprint("Parser. Agregar texto antes: linea 692\n");
            $$->buffer=(struct textoInforme *)agregarTextoAntes("writeLn\0",$$->buffer);
            yyprint("Parser. Agregar texto despues: linea 694 y 695\n");
            agregarTextoDespues("(\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);
            agregarTextoDespues(")\0",$$->buffer);
        } else
            $$=NULL;
    }

    ;         

proposicionDoWhile:  '{' listaProposiciones '}' {
                                        if($2!=NULL){
                                        int i = 0;
                                        $$=(struct id*)crearNodoId();
                                        
                                        yyprint("Parser. Agregar texto antes: linea 809\n");
                                        for(i=0;i<scope;i++)
                                            $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                        
                                        yyprint("Parser. Agregar texto despues: linea 842 al 854\n");
                                        
                                        agregarTextoDespues("\n\0",$$->buffer);
                                        
                                        agregarLista($2->buffer,$$->buffer);
                                        
                                        agregarTextoDespues("\n\0",$$->buffer);
                                        
                                        for(i=0;i<scope;i++)
                                            agregarTextoDespues("\t\0",$$->buffer);
                                        }else{
                                            $$=NULL;
                                        }
                                        
                                     }  

proposicion: ';'
    {
        int i=0;
        $$=(struct id*)crearNodoId();
        yyprint("Parser. Agregar texto antes: linea 709\n");
        for(i=0;i<scope;i++)
            $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
        
        yyprint("Parser. Agregar texto despues: linea 713 y 714\n");                    
        agregarTextoDespues(";\0",$$->buffer);
        agregarTextoDespues("\n\0",$$->buffer);
     }

    | expresion ';'
    {
        int i=0;
        
        if($1!=NULL){
            $$=(struct id*)crearNodoId();
            
            yyprint("Parser. Agregar texto antes: linea 726\n");
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
            agregarLista($1->buffer,$$->buffer);
            yyprint("Parser. Agregar texto despues: linea 730 y 731\n");
            agregarTextoDespues(";\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        }else
            $$=NULL;
    }

    | asignacion ';'
    {
        int i=0;
        
        if($1!=NULL){
            $$=(struct id*)crearNodoId();
            
            yyprint("Parser. Agregar texto antes: linea 745\n");
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
            agregarLista($1->buffer,$$->buffer);
            yyprint("Parser. Agregar texto despues: linea 749 y 750\n");
            agregarTextoDespues(";\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        } else
            $$=NULL;
    }

    | IF '(' expresionAsignacion ')' { incrementarScope(); } proposicion { decrementarScope(); } reglaElse
    {
        if($3!=NULL && $6!=NULL){
            int i=0;
            
            $$=(struct id*)crearNodoId();
            
            yyprint("Parser. Agregar texto antes: linea 764\n");
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
            yyprint("Parser. Agregar texto despues: linea 767 al 772\n");
            agregarTextoDespues("if \0",$$->buffer);
            agregarTextoDespues("(\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);
            agregarTextoDespues(") then\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
            agregarLista($6->buffer,$$->buffer);
            if($8!=NULL)
                agregarLista($8->buffer,$$->buffer);
                agregarTextoDespues("\n\0",$$->buffer);
        } else
            $$=NULL;
    }

    | FOR '(' expresionAsignacion ';' expresionAsignacion ';' expresionAsignacion ')' { incrementarScope(); } proposicion 
    {
        if($3!=NULL && $5!=NULL && $7!=NULL &&$10!=NULL){
            int i=0;
            
            $$=(struct id*)crearNodoId();
            yyprint("Parser. Agregar texto antes: linea 788\n");
                for(i=0;i<scope;i++)
                    $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
            yyprint("Parser. Agregar texto despues: linea 791 al 801\n");
            agregarTextoDespues("for\0",$$->buffer);
            agregarTextoDespues("(\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);
            agregarTextoDespues(";\0",$$->buffer);
            agregarLista($5->buffer,$$->buffer);
            agregarTextoDespues(";\0",$$->buffer);
            agregarLista($7->buffer,$$->buffer);
            agregarTextoDespues(")\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
            agregarLista($10->buffer,$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        } else
            $$=NULL;
    
        decrementarScope(); 
    }

    | WHILE '(' expresionAsignacion ')' { incrementarScope(); } proposicion 
    { 
        if($3!=NULL && $6!=NULL){
            int i=0;
        
            $$=(struct id*)crearNodoId();
            yyprint("Parser. Agregar texto antes: linea 816\n");
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
        
            yyprint("Parser. Agregar texto despues: linea 819 al 825\n");
            agregarTextoDespues("while\0",$$->buffer);
            agregarTextoDespues("(\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);
            agregarTextoDespues(") do\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
            agregarLista($6->buffer,$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        
        } else
            $$=NULL;

        decrementarScope(); 
    }

    | DO { incrementarScope(); } proposicionDoWhile WHILE '(' expresionAsignacion ')' ';'
    { 
        if($3!=NULL && $6!=NULL){
            int i=0;
        
            $$=(struct id*)crearNodoId();
            yyprint("Parser. Agregar texto antes: linea 816\n");
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
        
            yyprint("Parser. Agregar texto despues: linea 819 al 825\n");
            agregarTextoDespues("repeat\n\0",$$->buffer);
            agregarLista($3->buffer,$$->buffer);   
            
            agregarTextoDespues("until (not(\0",$$->buffer);
            agregarLista($6->buffer,$$->buffer);
            agregarTextoDespues("));\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        
        } else
            $$=NULL;

        decrementarScope(); 
    }
    
    | proposicionCompuesta

    | RETURN expresionAsignacion ';'
    {
        if($2!=NULL){
            int i=0;
        
            $$=(struct id*)crearNodoId();
            yyprint("Parser. Agregar texto antes: linea 843\n");
            for(i=0;i<scope;i++)
                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
            
            yyprint("Parser. Agregar texto despues: linea 846 al 849\n");        
            agregarTextoDespues("return \0",$$->buffer);
            agregarLista($2->buffer,$$->buffer);
            agregarTextoDespues(";\0",$$->buffer);
            agregarTextoDespues("\n\0",$$->buffer);
        } else
            $$=NULL;
    }

    | RETURN ';'
    {
        int i=0;
        $$=(struct id*)crearNodoId();
        yyprint("Parser. Agregar texto antes: linea 860\n");
        for(i=0;i<scope;i++)
            $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
        
        yyprint("Parser. Agregar texto despues: linea 863 y 864\n");
    //    agregarTextoDespues("\0",$$->buffer);
      //  agregarTextoDespues(";\0",$$->buffer);
     }

    | error ';'
    {
        $$=NULL; 
        yyerrok; 
    }

    ;


proposicionCompuesta:
         '{' '}'                 {
                                                int i =0;
                                                $$=(struct id*)crearNodoId();
                                                
                                                yyprint("Parser. Agregar texto antes: linea 791\n");
                                                for(i=0;i<scope;i++)
                                                    $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                                
                                                yyprint("Parser. Agregar texto despues: linea 822 al 830\n");
                                                /*agregarTextoDespues("{\0",$$->buffer);
                                                
                                                agregarTextoDespues("\n\0",$$->buffer);
                                                
                                                for(i=0;i<scope;i++)
                                                    agregarTextoDespues("\t\0",$$->buffer);
                                                
                                                agregarTextoDespues("}\0",$$->buffer);*/
                                 }                 
        | '{' listaProposiciones '}' {
                                        if($2!=NULL){
                                        int i = 0;
                                        $$=(struct id*)crearNodoId();
                                        
                                        yyprint("Parser. Agregar texto antes: linea 809\n");
                                        for(i=0;i<scope;i++)
                                            $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                        
                                        yyprint("Parser. Agregar texto despues: linea 842 al 854\n");
                                        agregarTextoDespues("begin\0",$$->buffer);
                                        
                                        agregarTextoDespues("\n\0",$$->buffer);
                                        
                                        agregarLista($2->buffer,$$->buffer);
                                        
                                        agregarTextoDespues("\n\0",$$->buffer);
                                        
                                        for(i=0;i<scope;i++)
                                            agregarTextoDespues("\t\0",$$->buffer);
        
                                        agregarTextoDespues("end;\0",$$->buffer);
                                        }else{
                                            $$=NULL;
                                        }
                                        
                                     }                    
        | '{' listaDeclaraciones '}'        {     
                                                int i =0;
                                                $$=(struct id*)crearNodoId();
                                                
                                                yyprint("Parser. Agregar texto antes: linea 834\n");
                                                for(i=0;i<scope;i++)
                                                    $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                                
                                                yyprint("Parser. Agregar texto despues: linea 869 al 875\n");
                                                agregarTextoDespues("begin\0",$$->buffer);
                                                
                                                agregarTextoDespues("\n\0",$$->buffer);
                                                
                                                for(i=0;i<scope;i++)
                                                    agregarTextoDespues("\t\0",$$->buffer);
                                                
                                                agregarTextoDespues("end\0",$$->buffer);
                                            }        
        | '{' listaDeclaraciones listaProposiciones '}' {   
                                                            if($3!=NULL){
                                                            int i = 0;
                                                            $$=(struct id*)crearNodoId();
                                                            
                                                            yyprint("Parser. Agregar texto antes: linea 852\n");
                                                            for(i=0;i<scope;i++)
                                                                $$->buffer=(struct textoInforme *)agregarTextoAntes("\t\0",$$->buffer);
                                                            
                                                            yyprint("Parser. Agregar texto despues: linea 887 al 899\n");
                                                            agregarTextoDespues("begin\n\0",$$->buffer);
                                                            //agregarTextoDespues("var\n\0",$$->buffer);

                                                            //agregarLista($2->buffer, $$->buffer);
                                                            //agregarTextoDespues("\nbegin\n\0",$$->buffer);
                                                            agregarLista($3->buffer, $$->buffer);
                                                            
                                                            agregarTextoDespues("\n\0",$$->buffer);
                                                            
                                                            for(i=0;i<scope;i++)
                                                                agregarTextoDespues("\t\0",$$->buffer);
                            
                                                            agregarTextoDespues("end;\0",$$->buffer);
                                                            }else{
                                                                $$=NULL;
                                                            }
                                                            
                                                        }        
        | error '}' { $$=NULL; yyerrok; }  
        ;            
            
expresionAsignacion:
                expresion { $$=$1; 
                          }
                | asignacion {
                               $$=$1;
                             }
                ;
            
declaracion: tipo listaVariables ';'                    {  
                                                        if($1!=TIPO_ERROR && $2!=NULL){
                                                            asignarDeclaradosTipo($1,$2);
                                                            $$=TIPO_VACIO;
                                                            agregar_tipo_vpf($1);
                                                        }else{
                                                            $$=TIPO_ERROR;
                                                        }
                                                     }
            | tipo listaVariables '=' expresion ';' { 
                                                      if($4!=NULL){
                                                          if($1!=$4->tipo){
                                                                errorSemantico(""," la expresion no es del tipo de las variables");
                                                                $$=TIPO_ERROR;
                                                           }else if($2!=NULL){
                                                                asignarDeclaradosTipo($1,$2);
                                                                agregar_tipo_vpf($1);
                                                                $$=TIPO_VACIO;
                                                           }
                                                       }else{
                                                            $$=TIPO_ERROR;
                                                       }
                                                    }
            ;                    

listaVariables:
        variable                 {     
                                        if((struct variable *)buscaVariableScope($1->lexema,scope)){
                                            errorSemantico($1->lexema,"la variable ya fue declarada\n");
                                            $$=NULL;
                                        }else{
                                            struct variable *v = (struct variable *)crearNodoVariable();
                                             v->lexema=strdup($1->lexema);
                                             v->compuesto=$1->compuesto;
                                             agregarVariable(v); 
                                             $$=&v->listaDeclarados;
                                             nueva_vpf ($1->lexema, AUN_SIN_TIPO, $1->compuesto, AUN_SIN_FUNCION);
                                        }
                                         
                                 }
        | listaVariables ',' variable {   if((struct variable *)buscaVariableScope($3->lexema,scope)){
                                            errorSemantico($3->lexema,"la variable ya fue declarada\n");
                                            $$=NULL;
                                          }else{
                                                struct variable *v = (struct variable *)crearNodoVariable();
                                                 v->lexema=strdup($3->lexema);
                                                 v->compuesto=$3->compuesto;
                                                 agregarVariable(v); 
                                                 nueva_vpf ($3->lexema, AUN_SIN_TIPO, $3->compuesto, AUN_SIN_FUNCION);

                                                if($1!=NULL){
                                                    agregarDeclaracion(&v->listaDeclarados,$1);
                                                    $$=$1;
                                                }else{
                                                    $$=NULL;
                                                }
                                           }
                                           
                                      }
        ;
            
listaExpresiones:  expresionAsignacion {      
                                if($1!=NULL){
                                     $$=(struct argumentos*)crearNodoArgumentos();
                                     agregarNodoArgumento($1->tipo,"",$$);
                                     $$->buffer=$1->buffer;
                                 }else{
                                    $$=NULL;
                                 }
                             }
                 | listaExpresiones ',' expresionAsignacion { 
                                                     if($1!=NULL){
                                                        $$=$1;
                                                        if($3!=NULL){
                                                            agregarNodoArgumento($3->tipo,"",$1);
                                                            yyprint("Parser. Agregar texto despues: linea 987\n");
                                                            agregarTextoDespues(",\0",$$->buffer);
                                                            agregarLista($3->buffer,$$->buffer);
                                                        }
                                                     }else{
                                                        $$=NULL;
                                                     }
                                                  }
                 |             {    $$=(struct argumentos*)crearNodoArgumentos();
                                 agregarNodoArgumento(TIPO_VACIO,"",$$);
                                 
                            }
                 |  listaExpresiones ',' error { yyerrok;
                                                    if($1!=NULL)
                                                        $$=$1;
                                                    else
                                                        $$=NULL;
                                                }
                 ;            

listaDeclaraciones: declaracion
                | listaDeclaraciones declaracion
                ;                 
                 
listaProposiciones: proposicion {
                                    if($1!=NULL){
                                        $$=$1;
                                    }else{
                                        $$=NULL;
                                    }
                                }
                | listaProposiciones proposicion {
                                                    if($1!=NULL){
                                                        $$=$1;
                                                        if($2!=NULL){
                                                            agregarLista($2->buffer,$1->buffer);
                                                        }
                                                    }else{
                                                        $$=NULL;
                                                    }
                                                 }
                ;
                                        
reglaElse:   ELSE { incrementarScope(); } proposicion
            {
                if($3!=NULL){
                
                $$=(struct id*)crearNodoId();
                
                yyprint("Parser. Agregar texto antes: linea 1002\n");
                $$->buffer=(struct textoInforme *)agregarTextoAntes("else\0",$$->buffer);
                
                yyprint("Parser. Agregar texto despues: linea 1039\n");
                agregarTextoDespues("\n\0",$$->buffer);
                
                agregarLista($3->buffer,$$->buffer);
                
                }else{
                    $$=NULL;
                }
                
                decrementarScope(); 
            }
             | { $$=NULL; }  %prec IFX
             ; 
            
asignacion: variable '=' expresion {

                                   if($1!=NULL && $3!=NULL){
                                   
                                   struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                            if(v->tipo != $3->tipo || v->compuesto != $1->compuesto){
                                                     errorSemantico(v->lexema," se intento asignar una expresion de distinto tipo\n");
                                                    $$=NULL;
                                            }else{
                                                $$=$1;
                                                yyprint("Parser. Agregar texto despues: linea 1068\n");
                                                agregarTextoDespues(" := \0",$$->buffer);
                                                agregarLista($3->buffer,$$->buffer);
                                            }
                                        }
                                    
                                    }
                                    
                                    
                                  }
            | variable PLUSPLUS {  
                                   if($1!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                                $$=$1;
                                                yyprint("Parser. Agregar texto despues: linea 1087\n");
                                                agregarTextoDespues(" := \0",$$->buffer);
                                                agregarTextoDespues($1->lexema,$$->buffer);
                                                agregarTextoDespues(" + 1\0",$$->buffer);
                                                
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                }
            | variable MINUSMINUS {  
                                    if($1!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                                $$=$1;
                                                yyprint("Parser. Agregar texto despues: linea 1103\n");
                                                agregarTextoDespues(" := \0",$$->buffer);
                                                agregarTextoDespues($1->lexema,$$->buffer);
                                                agregarTextoDespues(" - 1\0",$$->buffer);
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                }
            | variable PLUSEQUAL expresion {
                                    
                                  if($1!=NULL && $3!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                                if(v->tipo == $3->tipo){
                                                    $$=$1;
                                                    yyprint("Parser. Agregar texto despues: linea 1121\n");
                                                    agregarTextoDespues("+=\0",$$->buffer);
                                                    agregarLista($3->buffer,$$->buffer);
                                                }else{
                                                    errorSemantico($1->lexema," se intento asignar una expresion de distinto tipo\n");
                                                    $$=NULL;
                                                }
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                    
                                    
                                  }
            | variable MULEQUAL expresion {
            
                                   if($1!=NULL && $3!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                                if(v->tipo == $3->tipo){
                                                    $$=$1;
                                                    yyprint("Parser. Agregar texto despues: linea 1146\n");
                                                    agregarTextoDespues("*=\0",$$->buffer);
                                                    agregarLista($3->buffer,$$->buffer);
                                                }else{
                                                    errorSemantico($1->lexema," se intento asignar una expresion de distinto tipo\n");
                                                    $$=NULL;
                                                }
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                    
                                    
                                  }
            | variable DIVEQUAL expresion {
                                    if($1!=NULL && $3!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                                if(v->tipo == $3->tipo){
                                                    $$=$1;
                                                    yyprint("Parser. Agregar texto despues: linea 1170\n");
                                                    agregarTextoDespues("/=\0",$$->buffer);
                                                    agregarLista($3->buffer,$$->buffer);
                                                }else{
                                                    errorSemantico($1->lexema," se intento asignar una expresion de distinto tipo\n");
                                                    $$=NULL;
                                                }
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                    
                                  }
            | variable MINUSEQUAL expresion {
                                    if($1!=NULL && $3!=NULL){
                                        struct variable *v = (struct variable *)buscaVariable($1->lexema);

                                       if(v==NULL){
                                          errorSemantico($1->lexema," no fue declarada\n");
                                          $$=NULL;
                                       }else{
                                                if(v->tipo == $3->tipo){
                                                    $$=$1;
                                                    yyprint("Parser. Agregar texto despues: linea 1193\n");
                                                    agregarTextoDespues("-=\0",$$->buffer);
                                                    agregarLista($3->buffer,$$->buffer);
                                                }else{
                                                    errorSemantico($1->lexema," se intento asignar una expresion de distinto tipo\n");
                                                    $$=NULL;
                                                }
                                        }
                                    }else{
                                        $$=NULL;
                                    }
                                    
                                    
                                  }
            ;
%%

void
yyerror(char *tipo_de_error)
{    printf("%s: linea %d, cerca de \"%s\".\n", tipo_de_error, yylineno,
        yylval.lexema);
}


void
nueva_vpf (char *nombre, int tipo, int compuesto, int funcion)
{
    strcpy (variables_por_funcion[indice_vpf].nombre, nombre);
    variables_por_funcion[indice_vpf].tipo = tipo;
    variables_por_funcion[indice_vpf].compuesto = compuesto;
    variables_por_funcion[indice_vpf].funcion = funcion;
    
    indice_vpf++;
}

void
agregar_tipo_vpf (int tipo)
{
    int i;
    
    for (i = 0; i < CANTIDAD_VARIABLES; i++)
        if (variables_por_funcion[i].tipo == AUN_SIN_TIPO) 
            variables_por_funcion[i].tipo = tipo;
}

void
agregar_funcion_vpf (int funcion)
{
    int i;
    
    for (i = 0; i < CANTIDAD_VARIABLES; i++)
        if (variables_por_funcion[i].funcion == AUN_SIN_FUNCION) 
            variables_por_funcion[i].funcion = funcion;
}


